package ca.etsmtl.log660.businessLogic;
import ca.etsmtl.log660.entity.Film;
import ca.etsmtl.log660.entity.Copie;
import ca.etsmtl.log660.entity.Client;
import ca.etsmtl.log660.entity.Langue;
import ca.etsmtl.log660.entity.Genre;
import ca.etsmtl.log660.entity.Personnage;
import ca.etsmtl.log660.entity.Pays;


import ca.etsmtl.log660.businessLogic.ConnexionController;

import ca.etsmtl.log660.configuration.SessionFactoryHelper;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import org.hibernate.Hibernate;

import java.lang.*;
import java.util.*;


public class FilmController{   
   private FilmController(){ 

   } 	
   
   public static FilmController getInstance() { 
      if (instance == null) { 
         instance = new FilmController(); 
      } 
      return instance; 
   }
   
   public void rentFilm(Integer noFilm){
   		ArrayList<Copie> availableCopies = this.getAvailableCopiesOfAFilmByNoFilm(noFilm);
   		if(filmEnPossessionDuClient() < ConnexionController.getInstance().getForfait().getLocationMax())
	   	   	if(availableCopies.size() >= 1){
   		   		Copie copie = availableCopies.get(0);
   		   		Session session = SessionFactoryHelper.getSessionFactory().openSession();
   		   		session.beginTransaction();
   				Client client = ConnexionController.getInstance().getClient();
   				copie.setNoIndividu(client.getNoIndividu());
   				copie.setDateDebutLocation(new java.util.Date());
 				session.update(copie); 
 				session.getTransaction().commit(); 
				session.close();
   		   	}
   		   	else{
   		   		throw new RuntimeException("Il n'y a plus de copie disponible pour ce film");
   		   	}
   		 else{
   		 	throw new RuntimeException("Vous avez déjà en votre possession le nombre de film maximal permit par votre forfait");  
   		 }
   	}
   
   public static long  filmEnPossessionDuClient(){
   		Session session = SessionFactoryHelper.getSessionFactory().openSession();
   	   	session.beginTransaction();
   	   	int nbrFilmInPossession = 
   	   		(int)session.createQuery("From Copie C " +
   	   	                      	     "WHERE C.NoIndividu = " + 
   	   	                              ConnexionController.getInstance().getClient().getNoIndividu()).list().size();
		session.close();
   		return nbrFilmInPossession;
   }
   
   public Integer getnbrAvailableCopiesOfAFilmByNoFilm(Integer noFilm){
   		return getAvailableCopiesOfAFilmByNoFilm(noFilm).size();
   }
   
   private ArrayList<Copie> getAvailableCopiesOfAFilmByNoFilm(Integer noFilm){
   		Copie copie;
   		Session session = SessionFactoryHelper.getSessionFactory().openSession();
		session.beginTransaction();
		List lesCopies = session.createQuery("From Copie C Where C.NoFilm =" + noFilm + 
											 " and C.NoIndividu is null" ).list();
		session.getTransaction().commit();
		session.close();
		
		ArrayList<Copie> copies = new ArrayList<Copie>();
		for(Iterator iCopie = lesCopies.iterator(); iCopie.hasNext();){
			copie = (Copie) iCopie.next();
			copies.add(copie);
		}
		return copies;
   }
   
   //**titre** - **Annee** - **pays de production** - **Langue** - **Genre** - 
   public ArrayList<Film> getFilms(String titre, String langue,
                                   int anneeProductionMin, int anneeProductionMax,
                                   ArrayList<String> acteurs, String realisateur,
                                   ArrayList<String> genres, ArrayList<String> payss){ 
   		Film film;
   		Session session = SessionFactoryHelper.getSessionFactory().openSession();
		session.beginTransaction();
		String requete = rechercheFilmRequeteContructeur(titre, langue, 
														 anneeProductionMin, anneeProductionMax, acteurs, realisateur,
														 genres, payss);
		List lesFilms = session.createSQLQuery(requete).addEntity(Film.class).list();
		session.getTransaction().commit();
		session.close();
		
		ArrayList<Film> films = new ArrayList<Film>();
		for(Iterator iFilm = lesFilms.iterator(); iFilm.hasNext();){
			film = (Film) iFilm.next();
			films.add(film);
		}
		return films;
   }
      
	private static FilmController instance;
   

    //Creation Requetes pour rechercher film
	//requete de bases
	private static String requeteRechercheFilmBase(String titre, String langue, int anneeProductionMin, int anneeProductionMax){
   		String requete = "SELECT F.NoFilm, F.Titre, F.Annee, F.Synopsis, F.Duree, F.NomLangue, F.NoRealisateur FROM Film F WHERE lower(titre) like '%" + titre.toLowerCase() + "%'";
   		if(!langue.isEmpty())
   			requete += " and lower(nomLangue) = '" + langue.toLowerCase() + "'";
   		if(anneeProductionMin != -1)
   			requete += " and annee >= " + anneeProductionMin;
   		if(anneeProductionMax != -1)
   			requete += " and annee <= " + anneeProductionMax;
   		return requete;
   	}
   	
   	private static String requeteRechercheFilmParGenre(String genre){
   		String requete = "SELECT DISTINCT F.NoFilm, F.Titre, F.Annee, F.Synopsis, F.Duree, F.NomLangue, F.NoRealisateur FROM Film F " +
   						 "JOIN FilmGenre ON FilmGenre.NoFilm = F.NoFilm WHERE lower(NomGenre) = '" + genre.toLowerCase() + "'";
   		return requete;
   	}
   	
   	private static String requeteRechercheFilmParPays(String pays){
   		String requete = "SELECT DISTINCT F.NoFilm, F.Titre, F.Annee, F.Synopsis, F.Duree, F.NomLangue, F.NoRealisateur FROM Film F " +
   						 "JOIN FilmPays P ON P.NoFilm = F.NoFilm  WHERE lower(NomPays) = '" + pays.toLowerCase() + "'";
   		return requete;
   	}
   	
   	private static String requeteRechercheFilmParActeur(String acteur){
   		String requete = "SELECT DISTINCT F.NoFilm, F.Titre, F.Annee, F.Synopsis, F.Duree, F.NomLangue, F.NoRealisateur FROM Film F " +
  						 "JOIN filmpersonnageacteur ON filmpersonnageacteur.nofilm = F.nofilm " +
  						 "JOIN personne ON filmpersonnageacteur.noacteur = personne.nopersonne " +
 						 "WHERE lower(Prenom||' '||Nom) like '%" + acteur.toLowerCase() + "%'";
   		return requete;
   	}
   	
   	private static String requeteRechercheFilmParRealisateur(String realisateur){
   		String requete = "SELECT DISTINCT F.NoFilm, F.Titre, F.Annee, F.Synopsis, F.Duree, F.NomLangue, F.NoRealisateur FROM film F " +
  						 "JOIN Personne ON F.NoRealisateur = Personne.NoPersonne " +
   		 				 "WHERE lower(Prenom||' '||Nom) like '%" + realisateur.toLowerCase() + "%'";
   		return requete;
   	} 
   	
   	
   	//Retourne la liste exaustive des Langues
   	public static ArrayList<Langue> getLangues(){
   		Session session = SessionFactoryHelper.getSessionFactory().openSession();
		session.beginTransaction();
		Langue langue;
		List lesLangues = session.createQuery("From Langue L").list();
	 	ArrayList<Langue> langues = new ArrayList<Langue>();
		for(Iterator iLangue = lesLangues.iterator(); iLangue.hasNext();){
			langue = (Langue) iLangue.next();
			langues.add(langue);
		}
   		return langues;
   	}
   	
   	public static ArrayList<Pays> getPays(){
   		Session session = SessionFactoryHelper.getSessionFactory().openSession();
		session.beginTransaction();
		Pays Pays;
		List lesPays = session.createQuery("From Pays P").list();
	 	ArrayList<Pays> Payss = new ArrayList<Pays>();
		for(Iterator iPays = lesPays.iterator(); iPays.hasNext();){
			Pays = (Pays) iPays.next();
			Payss.add(Pays);
		}
   		return Payss;
   	}
   	
   	//Retourne la liste exaustive des Genres
   	public static ArrayList<Genre> getGenres(){
   		Session session = SessionFactoryHelper.getSessionFactory().openSession();
		session.beginTransaction();
		Genre Genre;
		List lesGenres = session.createQuery("From Genre G").list();
	 	ArrayList<Genre> Genres = new ArrayList<Genre>();
		for(Iterator iGenre = lesGenres.iterator(); iGenre.hasNext();){
			Genre = (Genre) iGenre.next();
			Genres.add(Genre);
		}
   		return Genres;
   	}
   	
   	private static String rechercheFilmRequeteContructeur(String titre, String langue,
                                   int anneeProductionMin, int anneeProductionMax,
                                   ArrayList<String> acteurs, String realisateur,
                                   ArrayList<String> genres, ArrayList<String> payss){
        String requeteConstruite = "";
        ArrayList<String> requetesACombiner = new ArrayList<String>();
    	//Gestion de la requête de base 
       	requetesACombiner.add(requeteRechercheFilmBase(titre, langue, anneeProductionMin, anneeProductionMax));
       	
       	//Gestion des genre
       	if(genres.size() > 0){
       		for(String genre : genres){
       			requetesACombiner.add(requeteRechercheFilmParGenre(genre));
      		}
       	}
       	
       	//Gestion des pays
       	if(payss.size() > 0){
       		for(String pays : payss){
       			requetesACombiner.add(requeteRechercheFilmParPays(pays));
      		}
       	}
       	
       	//Gestion des acteurs
       	if(acteurs.size() > 0){
       		for(String acteur : acteurs){
       			requetesACombiner.add(requeteRechercheFilmParActeur(acteur));
      		}
       	}
       	
       	//Gestion des realisateurs
       	if(!realisateur.isEmpty()){
       		requetesACombiner.add(requeteRechercheFilmParRealisateur(realisateur));
       	}
       	
       	for(int i = 0; i < requetesACombiner.size(); i++){
       		requeteConstruite += requetesACombiner.get(i);
       		if(i < requetesACombiner.size() - 1){
       			requeteConstruite += " INTERSECT ";
       		}
       	}
       	return requeteConstruite;
    }
    
    public static Film getTouteLesInformationsFilms(Film film){
    	Film filmARetourner;
    	Session session = SessionFactoryHelper.getSessionFactory().openSession();
		session.beginTransaction();
		
		List lesFilms = session.createQuery("From Film F WHERE F.NoFilm = " + film.getNoFilm()).list();
		Iterator iFilm = lesFilms.iterator(); 
		filmARetourner = (Film) iFilm.next();
                Hibernate.initialize(filmARetourner.getRealisateur());
		Hibernate.initialize(filmARetourner.getLesGenres());
		Hibernate.initialize(filmARetourner.getLesPays());
		Hibernate.initialize(filmARetourner.getLesScenaristes());
		Hibernate.initialize(filmARetourner.getLesActeurs());
		session.close();	
		return filmARetourner;
    }
    
    public static ArrayList<String> getPersonnageByFilmActeur(int noFilm, int noActeur){
    	ArrayList<String> personnages = new ArrayList<String>();
    	Session session = SessionFactoryHelper.getSessionFactory().openSession();
		session.beginTransaction();
    	List lesPersonnages = session.createSQLQuery("SELECT Nom FROM Personnage P " + 
                                                                "JOIN FilmPersonnageActeur FPA ON " +
                                                                "FPA.NoPersonnage = P.NoPersonnage " +
                                                                "WHERE FPA.NoFilm = " + noFilm +
                                                                " AND FPA.NoActeur = " + noActeur).list();
    	for(Iterator iPersonnage = lesPersonnages.iterator(); iPersonnage.hasNext();){
			String personnage = (String) iPersonnage.next();
			personnages.add(personnage);
		}
		session.close();	
		return personnages;
    }
}